package tutor;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.util.glu.GLU.*;
import static org.lwjgl.input.Keyboard.*;


import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.vector.Vector3f;

public class Tutorial7 extends Game {

    // VBO Vertex ID
    int vboVertexID;
    // VBO Color ID
    int vboColorID;
    
    // FloatBuffer for projection matrix
    FloatBuffer projBuffer;
    // FloatBuffer for view matrix
    FloatBuffer viewBuffer;
    
    ShaderProgram shaderProgram;
    
    Camera camera;
    
    /**
     * Initialize resources
     */
    public void init() {
    	
    	Display.setTitle("3d test 3");
    	
    	camera = new Camera(45, (float) Display.getWidth() / (float) Display.getHeight(), 0.1f, 100f);
    	camera.setPosition(new Vector3f(0, 0, -3));        
    	
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
    	
        // Create Pyramid Vertex Buffer
        FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(3*24);
        vertexBuffer.put(new float[]
        {
        	    // Front face
        	    -0.5f, +0.5f, +0.5f,
        	    +0.5f, +0.5f, +0.5f,
        	    -0.5f, -0.5f, +0.5f,
        	    +0.5f, -0.5f, +0.5f,

        	    // Right face
        	    +0.5f, +0.5f, +0.5f,
        	    +0.5f, +0.5f, -0.5f,
        	    +0.5f, -0.5f, +0.5f,
        	    +0.5f, -0.5f, -0.5f,

        	    // Back face
        	    +0.5f, +0.5f, -0.5f,
        	    -0.5f, +0.5f, -0.5f,
        	    +0.5f, -0.5f, -0.5f,
        	    -0.5f, -0.5f, -0.5f,

        	    // Left face
        	    -0.5f, +0.5f, -0.5f,
        	    -0.5f, +0.5f, +0.5f,
        	    -0.5f, -0.5f, -0.5f,
        	    -0.5f, -0.5f, +0.5f,

        	    // Top face
        	    -0.5f, +0.5f, +0.5f,
        	    +0.5f, +0.5f, +0.5f,
        	    -0.5f, +0.5f, -0.5f,
        	    +0.5f, +0.5f, -0.5f,

        	    // Bottom face
        	    -0.5f, -0.5f, +0.5f,
        	    +0.5f, -0.5f, +0.5f,
        	    -0.5f, -0.5f, -0.5f, 
        	    +0.5f, -0.5f, -0.5f
        });
        vertexBuffer.rewind();
        
        // Create Pyramid Color Buffer
        FloatBuffer colorBuffer = BufferUtils.createFloatBuffer(3*24);
        colorBuffer.put(new float[]
        {
            1, 0, 0,
            0, 1, 0,
            0, 0, 1,
            
            1, 1, 1,
            0, 1, 0,
            0, 0, 1,
            
            1, 0, 0,
            0, 1, 0,
            1, 0, 1, 
            
            1, 1, 0,
            0, 1, 1,
            1, 0, 1,
            
            1, 0, 1,
            0, 1, 0,
            1, 0, 1,
            
            1, 0, 0,
            0, 1, 0,
            0, 1, 0,
        });
        colorBuffer.rewind();
        
        // Create Vertex VBO
        vboVertexID = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
        glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        
        // Create Color VBO
        vboColorID = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboColorID);
        glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        
        // Create shader program
        shaderProgram = new ShaderProgram();
        shaderProgram.attachVertexShader("tutor/shader.vert");
        shaderProgram.attachFragmentShader("tutor/shader.frag");
        shaderProgram.link();
    }
    
    /**
     * Update logic
     */
    public void update(long elapsedTime)
    {
        if (isKeyDown(Keyboard.KEY_ESCAPE))
            end();

        // Look up
        if (isKeyDown(KEY_UP))
            camera.addRotation(-1f, 0, 0);

        // Look down
        if (isKeyDown(KEY_DOWN))
            camera.addRotation(1f, 0, 0);

        // Turn left
        if (isKeyDown(KEY_LEFT))
            camera.addRotation(0, -1f, 0);

        // Turn right
        if (isKeyDown(KEY_RIGHT))
            camera.addRotation(0, 1f, 0);

        // Move front
        if (isKeyDown(KEY_W))
            camera.move(0.1f, 1);

        // Move back
        if (isKeyDown(KEY_S))
            camera.move(-0.1f, 1);

        // Strafe left
        if (isKeyDown(KEY_A))
            camera.move(0.1f, 0);

        // Strafe right
        if (isKeyDown(KEY_D))
            camera.move(-0.1f, 0);
    }
    
    /**
     * Render to the screen
     */
    public void render()
    {
        // Set Camera View
        camera.apply();

        // Bind the shaders
        shaderProgram.bind();

        // Set the uniforms
        shaderProgram.setUniform("projection", camera.getProjectionMatrix());
        shaderProgram.setUniform("view", camera.getViewMatrix());

        // Clean both color and depth buffers
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Bind the vertex VBO
        glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
        glVertexPointer(3, GL_FLOAT, 0, 0);

        // Bind the color VBO
        glBindBuffer(GL_ARRAY_BUFFER, vboColorID);
        glColorPointer(3, GL_FLOAT, 0, 0);

        // Draw the cube with triangle strip
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 24);

        // Unbind the shaders
        ShaderProgram.unbind();
    	
//    	// Use shader
//    	shaderProgram.bind();
//    	
//        // Clean both color and depth buffers
//        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//
//        // Translate into the view
//        glTranslatef(0, 0, -2);
//
//        // Rotate on both x and y axes
//        glRotatef(2, 2, 2, 0);
//
//        // Enable client states
//        glEnableClientState(GL_VERTEX_ARRAY);
//        glEnableClientState(GL_COLOR_ARRAY);
//        
//        // Bind the vertex VBO
//        glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
//        glVertexPointer(3, GL_FLOAT, 0, 0);
//
//        // Bind the color VBO
//        glBindBuffer(GL_ARRAY_BUFFER, vboColorID);
//        glColorPointer(3, GL_FLOAT, 0, 0);
//
//        // Draw the cube with triangle strip
//        glDrawArrays(GL_TRIANGLE_STRIP, 0, 24);
//
//        // Translate back
//        glTranslatef(0, 0, 2);
//        
//     // Disable shader
//        ShaderProgram.unbind();
    }
    
    /**
     * Display resized
     */
    public void resized()
    {
        glViewport(0, 0, Display.getWidth(), Display.getHeight());
    }
    
    /**
     * Dispose resources
     */
    public void dispose()
    {
        glDeleteBuffers(vboVertexID);
        glDeleteBuffers(vboColorID);
        shaderProgram.dispose();
        
    }
    
    public static void main(String[] args)
    {
        new Tutorial7();
    }
}
